﻿/* Author: Achim Schnell */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using AppFx.Parsing;

namespace AppFx.Evaluation
{
    /// <summary>
    /// Evaluates RPN-tokens using DynamicMethod.
    /// </summary>
    public class DynamicMethodRpnEvaluator
    {
        public object Create(IList<IParsedToken> tokens)
        {
            DynamicMethod method = new DynamicMethod("Test", typeof(double), null);
            ILGenerator il = method.GetILGenerator();

            foreach (var token in tokens)
            {
                switch(token.ParsedType)
                {
                    case eParsedTokenType.Number:
                        il.Emit(OpCodes.Ldc_R8, double.Parse(token.Content));
                        break;
                    case eParsedTokenType.Operator:
                        switch (token.Content)
                        {
                            case "+":
                                il.Emit(OpCodes.Add);
                                break;
                            case "-":
                                il.Emit(OpCodes.Sub);
                                break;
                            case "*":
                                il.Emit(OpCodes.Mul);
                                break;
                            case "/":
                                il.Emit(OpCodes.Div);
                                break;
                        }
                        break;
                }
            }
            il.Emit(OpCodes.Ret);

            //il.Emit(OpCodes.Ldc_R8, 10.25);
            //il.Emit(OpCodes.Ldc_R8, 20.69);
            //il.Emit(OpCodes.Add);
            //il.Emit(OpCodes.Ret);

            return method.InvokeStatic();
        }
    }

    public static class MethodExtensions
    {
        public static object InvokeStatic(this DynamicMethod method,
            params object[] args)
        {
            return method.Invoke(null, args);
        }
        public static T InvokeStatic<T>(this DynamicMethod method,
            params object[] args)
        {
            return (T)method.InvokeStatic(args);
        }
    }
}
